package com.yc.spring.jdbc.bank.biz;

import com.yc.spring.jdbc.bank.bean.Account;
import com.yc.spring.jdbc.bank.dao.AccountDao;
import com.yc.spring.jdbc.bank.dao.RecordDao;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * 注册: insert(account), insert(record)
 * 存取款  update(account), insert(record)
 * 转账   update(account1),update(account2),
 *        insert(record), insert(record)
 * 查询交易明细 select(record)
 * 查询账号信息  selectById(account)
 */

@Transactional(rollbackFor = BizException.class)
// 类上的事务注解, 可以控制该类所有的业务方法, 如果方法上也加了事务注解,
//  配置属性与类上事务注解属性不一致, 遵循就近原则
/**
 * transactionManager == value ==> 设置事务管理器对象的 name
 * timeout 设置事务等待时间, 默认 -1, 等待时间不限制
 * propagation : 传播行为设置
 * isolation : 隔离级别
 * rollbackFor : 回滚异常
 * noRollbackFor : 非回滚异常
 *
 */
@Service
public class BankBiz {

    @Resource
    private AccountDao adao;
    @Resource
    private RecordDao rdao;

    // 存取款

    /**
     * 默认情况下, Spring的事务只会对 RuntimeException 及其子类进行回滚
     *  如果希望编译期异常也回滚, 那么必须设置 rollbackFor
     *  反之, 如果希望某些 运行时异常 不回滚, 也必须设置 noRollbackFor
     */
//    @Transactional(rollbackFor = BizException.class,
//            noRollbackFor = NullPointerException.class)
    @Transactional()
    public void save(long accountid, double money) throws BizException {
        if(accountid <= 0){
            throw new BizException("请输入账号!");
        }
        if(money == 0){
            throw new BizException("请输入金额!");
        }
        if(money<0){
            Account account = adao.selectById(accountid);
            if(account.getBalance() < -money){
                throw new BizException("账号余额不足!");
            }
        }
        adao.update(accountid,money);
        //int i = 1/0;  // 运行时异常
        rdao.insert(accountid,money);
    }

    // 转账
    public void transfer(int aid1, int aid2, int money) throws BizException {
        money = Math.abs(money);
        save(aid2, money); // 先存款
        save(aid1, -money);// 在取款
    }
}
